﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Wolfy.NetDisk.Core;
using Wolfy.NetDisk.Core.Model;
using Wolfy.NetDisk.Core.Repository;
using Wolfy.NetDisk.Infrastructure;

namespace Wolfy.NetDisk.Data
{
    public class Repository<T> : IRepository<T> where T : Entity, new()
    {
        /// <summary>
        /// 数据库上下文
        /// </summary>
        protected readonly DbContext db;
        /// <summary>
        /// 仓储类构造函数
        /// </summary>
        /// <param name="factory"></param>
        public Repository(IDbContextFactory factory)
        {
            this.db = factory.GetContext();
        }
        /// <summary>
        /// 根据id查找实体
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public T Get(int id)
        {
            var entity = this.db.Set<T>().Find(id);
            if (entity == null)
            {
                throw new NetDiskException("this entity doesn't exist anymore");
            }
            return entity;
        }
        /// <summary>
        /// 查找所有
        /// </summary>
        /// <returns></returns>
        public IQueryable<T> GetAll()
        {
            if (typeof(IDelete).IsAssignableFrom(typeof(T)))
            {
                return IoC.Resolve<IDeleteRepository<T>>().GetAll();
            }
            return db.Set<T>();
        }
        /// <summary>
        /// 条件
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="showDeleted"></param>
        /// <returns></returns>
        public IQueryable<T> Where(Expression<Func<T, bool>> predicate, bool showDeleted = false)
        {
            if (typeof(IDelete).IsAssignableFrom(typeof(T)))
            {
                return IoC.Resolve<IDeleteRepository<T>>().Where(predicate, showDeleted);
            }
            return this.db.Set<T>().Where(predicate);
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public T Insert(T entity)
        {
            this.db.Set<T>().Add(entity);
            return entity;
        }
        /// <summary>
        /// 保存
        /// </summary>
        public void Save()
        {
            this.db.SaveChanges();
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity"></param>
        public void Delete(T entity)
        {
            if (entity is IDelete)
            {
                (entity as IDelete).IsDeleted = true;
            }
            else
            {
                this.db.Set<T>().Remove(entity);
            }
        }
        /// <summary>
        /// 还原
        /// </summary>
        /// <param name="entity"></param>
        public void Restory(T entity)
        {
            if (entity is IDelete)
            {
                IoC.Resolve<IDeleteRepository<T>>().Restore(entity);
            }
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="totalRecord"></param>
        /// <param name="where"></param>
        /// <param name="isAsc"></param>
        /// <param name="orderLambda"></param>
        /// <returns></returns>
        public IQueryable<T> FindPaged(int pageIndex, int pageSize, out int totalRecord, Expression<Func<T, bool>> where, bool isAsc, Expression<Func<T, dynamic>> orderLambda)
        {
            var lst = this.db.Set<T>().Where<T>(where);
            totalRecord = lst.Count();
            if (!isAsc)
            {
                lst = lst.OrderByDescending<T, dynamic>(orderLambda);
            }
            return lst.Skip<T>((pageIndex - 1) * pageIndex).Take(pageSize);
        }

        /// <summary>
        /// 更新 
        /// </summary>
        /// <param name="item">更新对象</param>
        /// <returns></returns>
        public T Update(T item)
        {
            T tentity = this.db.Set<T>().Attach(item);
            this.db.Entry<T>(item).State = System.Data.Entity.EntityState.Modified;
            return tentity;
        }
    }
}
